package main

import (
	"bytes"
	"encoding/binary"
	"LterServer/model"
	"LterServer/util"
	"net"
	"time"

	"gitee.com/konyshe/gogo"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
)

const PCAP_PKT_HEADER_LEN = 56

type ProPayloadData struct {
	payLoad   []byte
	len       int
	pLterAddr *net.UDPAddr
}

type ProPayload struct {
	mpConn  *net.UDPConn
	mbDebug bool
}

func NewProPayload(conn *net.UDPConn, debug bool) *ProPayload {
	c := &ProPayload{conn, debug}
	return c
}

func (*ProPayload) Release() {
	pProRePlayTask.SendRelease()
	pProPacketTask.SendRelease()
}

func (c *ProPayload) Proc(data *ProPayloadData) (err error) {
	nowTime := time.Now()

	//简单的错误判断
	if data.len == 0 || data.payLoad == nil {
		model.CheckLterClientInfoMap(nowTime.Unix())
		return
	}

	buf := bytes.NewBuffer(data.payLoad[0:2])

	var nNeedDecodAesLen uint16
	binary.Read(buf, binary.BigEndian, &nNeedDecodAesLen)

	//错误判断，需要解密的长度怎么可能会大于实际长度
	if int(nNeedDecodAesLen) != data.len-2 {
		gogo.LogErrorF("异常报文内容(%d):\n % x\n", data.len, data.payLoad)
		return
	}

	var aeskey = []byte("!#%&(08642qeTUOadgjlzcb)")

	DecryptBytes := util.AES_CBC_Decrypt(data.payLoad[2:nNeedDecodAesLen+2], aeskey)
	nTag := DecryptBytes[45]

	//判断是否心跳包
	if nTag == 0 {
		if c.mpConn != nil {
			_, err = c.mpConn.WriteToUDP(data.payLoad[:data.len], data.pLterAddr)
		}

		if data.pLterAddr != nil {
			model.AddLterClientInfo(data.pLterAddr.String(), nowTime)
		}

		return
	}

	var tellNum uint64
	var imsiUint64 uint64
	var ReplayRawBuffer *bytes.Buffer
	var IPVersion byte

	switch nTag {
	case 0x04: // NAS短信,这只是个结构体，没有IP头
		{
			ethernetLayer := &layers.Ethernet{
				SrcMAC: net.HardwareAddr{0x02, 0x02, 0x02, 0x02, 0x02, 0x02},
				DstMAC: net.HardwareAddr{0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
			}

			ipLayer := &layers.IPv4{
				SrcIP: net.IP{2, 2, 2, 2},
				DstIP: net.IP{1, 1, 1, 1},
			}

			udpLayer := &layers.UDP{
				SrcPort: layers.UDPPort(4321),
				DstPort: layers.UDPPort(80),
			}

			buffer := gopacket.NewSerializeBuffer()
			gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{},
				ethernetLayer,
				ipLayer,
				udpLayer,
				gopacket.Payload(DecryptBytes[PCAP_PKT_HEADER_LEN:]),
			)

			ReplayRawBuffer = bytes.NewBuffer(buffer.Bytes())
			ReplayRawBuffer.Write(DecryptBytes[:PCAP_PKT_HEADER_LEN])
		}

	default: // 其他都有IP头，不过可能是IPv4或者IPv6
		{
			ReplayRawBuffer = bytes.NewBuffer([]byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}) //以太网头部的源宿MAC

			IPVersion = DecryptBytes[PCAP_PKT_HEADER_LEN] >> 4

			if IPVersion == 4 {
				ReplayRawBuffer.Write([]byte{0x08, 0x00})
			} else if IPVersion == 6 {
				ReplayRawBuffer.Write([]byte{0x86, 0xdd})
			} else {
				gogo.LogError("The pcap is not IPv4 and not IPv6 ?")
			}

			ReplayRawBuffer.Write(DecryptBytes[PCAP_PKT_HEADER_LEN:])
			ReplayRawBuffer.Write(DecryptBytes[:PCAP_PKT_HEADER_LEN])
		}
	}

	if pProRePlayTask != nil {
		err = pProRePlayTask.Push(ReplayRawBuffer.Bytes())
	}

	//提取手机号码
	phoneNumBuf := bytes.NewBuffer([]byte{0})
	phoneNumBuf.Write(ReplayRawBuffer.Bytes()[ReplayRawBuffer.Len()-40 : ReplayRawBuffer.Len()-33])
	binary.Read(phoneNumBuf, binary.BigEndian, &tellNum)

	//提取IMSI
	imsiBuf := bytes.NewBuffer([]byte{0})
	imsiBuf.Write(ReplayRawBuffer.Bytes()[ReplayRawBuffer.Len()-26 : ReplayRawBuffer.Len()-19])
	binary.Read(imsiBuf, binary.BigEndian, &imsiUint64)

	if pProPacketTask != nil {
		err = pProPacketTask.Push(&model.ProPacketData{
			tellNum,
			imsiUint64,
			data.pLterAddr.String(),
			"", "", 0, 0,
			IPVersion,
			0, 0,
			DecryptBytes[PCAP_PKT_HEADER_LEN:],
			nowTime})
	}

	model.UpLterPhoneInfo(tellNum, data.pLterAddr.String(), imsiUint64, data.len, 1)
	model.AddLterClientInfoPcapNum(data.pLterAddr.String(), 1, nowTime)

	return
}
